//
// Created by lz on 2021/2/23.
//

#ifndef MYWEBLIB_BASE_MUTEX_H_
#define MYWEBLIB_BASE_MUTEX_H_

#include "base/CurrentThread.h"
#include "base/noncopyable.h"
#include <assert.h>
#include <pthread.h>

//if defined 可以后接elif defined，可以多个选择，而 ifdef 只能接 else，在两个中选择，提供的逻辑都是差不多
//__attribute__ 是GNU C的一大特色



/*
 * Clang的线程安全分析是一个C++的扩展，用于对代码中潜在的竞争条件进行预警。
 * 该分析完全是静态的（即编译期间），不会有运行时的性能损耗。
 * 该分析当前仍处于开发阶段，但是对于在部署在工业中使用而言已经足够成熟了。
 * 它是由Google公司开发的，且与CERT/SEI一起合作，已经在Google的内部代码中广泛使用了。
 */

// so 如果用GCC来编译，下面的宏应该不会由有任何作用吧，而用clang编译的话， 在编译过程中，编译器会给出一些警告信息？

// Thread safety annotations {
// https://clang.llvm.org/docs/ThreadSafetyAnalysis.html

// Enable thread safety attributes only with clang.
// The attributes can be safely erased when compiling with other compilers.
#if defined(__clang__) && (!defined(SWIG))
#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
#else
#define THREAD_ANNOTATION_ATTRIBUTE__(x)
#endif

#define CAPABILITY(x) \
        THREAD_ANNOTATION_ATTRIBUTE__(capability(x))

#define SCOPED_CAPABILITY \
  THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)

#define GUARDED_BY(x) \
  THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))

#define PT_GUARDED_BY(x) \
  THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))

#define ACQUIRED_BEFORE(...) \
  THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))

#define ACQUIRED_AFTER(...) \
  THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))

#define REQUIRES(...) \
  THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))

#define REQUIRES_SHARED(...) \
  THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))

#define ACQUIRE(...) \
  THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))

#define ACQUIRE_SHARED(...) \
  THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))

#define RELEASE(...) \
  THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))

#define RELEASE_SHARED(...) \
  THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))

#define TRY_ACQUIRE(...) \
  THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))

#define TRY_ACQUIRE_SHARED(...) \
  THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))

#define EXCLUDES(...) \
  THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))

#define ASSERT_CAPABILITY(x) \
  THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))

#define ASSERT_SHARED_CAPABILITY(x) \
  THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))

#define RETURN_CAPABILITY(x) \
  THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))

#define NO_THREAD_SAFETY_ANALYSIS \
  THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)

// End of thread safety annotations }



#ifdef CHECK_PTHREAD_RETURN_VALUE

#ifdef NDEBUG
__BEGIN_DECLS
extern void __assert_perror_fail (int errnum,
								  const char *file,
								  unsigned int line,
								  const char *function)
	noexcept __attribute__ ((__noreturn__));
__END_DECLS
#endif

//__typeof__ () = typeof() 得到表达式的类型
#define MCHECK(ret) ({ __typeof__ (ret) errnum = (ret);         \
					   if (__builtin_expect(errnum != 0, 0))    \
						 __assert_perror_fail (errnum, __FILE__, __LINE__, __func__);})

#else  // CHECK_PTHREAD_RETURN_VALUE

#define MCHECK(ret) ({ __typeof__ (ret) errnum = (ret);         \
                       assert(errnum == 0); (void) errnum;})

#endif // CHECK_PTHREAD_RETURN_VALUE

namespace lzweb
{
	//MutexLock的使用示例
	// Use as data member of a class, eg.
	//
	// class Foo
	// {
	//  public:
	//   int size() const;
	//
	//  private:
	//   mutable MutexLock mutex_;
	//   std::vector<int> data_ GUARDED_BY(mutex_);
	// };
	class CAPABILITY("mutex") MutexLock : noncopyable
	{
	 public:
		MutexLock()
		:holder_(0)
		{
			// MCHECK 检查返回值是否为零，不为零直接崩溃。
			MCHECK(pthread_mutex_init(&mutex_,NULL));
		}
		~MutexLock()
		{
			assert(holder_ == 0);
			MCHECK(pthread_mutex_destroy(&mutex_));
		}
		// must be called when locked, i.e. for assertion
		bool isLockedByThisThread() const
		{
			return holder_ == CurrentThread::tid();
		}

		void assertLocked() const ASSERT_CAPABILITY(this)
		{
			assert(isLockedByThisThread());
		}

		// internal usage

		void lock() ACQUIRE()
		{
			MCHECK(pthread_mutex_lock(&mutex_));
			assignHolder();
		}

		void unlock() RELEASE()
		{
			unassignHolder();
			MCHECK( pthread_mutex_unlock(&mutex_));
		}

		pthread_mutex_t* getPthreadMutex()
		{
			return &mutex_;
		}




	 private:
		friend class Condition;   //条件变量类；
		class UnassignGuard : noncopyable    // unassigned -> 未赋值的
		{
		 public:
			explicit UnassignGuard(MutexLock& owner)
				: owner_(owner)
			{
				owner_.unassignHolder();
			}

			~UnassignGuard()
			{
				owner_.assignHolder();
			}

		 private:
			MutexLock& owner_;
		};


		//去除线程标志
		void unassignHolder()
		{
			holder_ = 0;
		}
		//设置当前线程标志
		void assignHolder()
		{
			holder_ = CurrentThread::tid();
		}

		pthread_mutex_t mutex_;   //互斥锁
		pid_t holder_;    // 持有线程

	};

	// MutexLockGuard的使用示例
	// Use as a stack variable, eg.
	// int Foo::size() const
	// {
	//   MutexLockGuard lock(mutex_);
	//   return data_.size();
	// }
	class SCOPED_CAPABILITY MutexLockGuard: noncopyable
	{
	 public:
		explicit MutexLockGuard(MutexLock& mutex) ACQUIRE(mutex)
		:mutex_(mutex)
		{
			mutex.lock();
		}

		~MutexLockGuard()
		{
			mutex_.unlock();
		}

	 private:
		MutexLock& mutex_;   //使用引用，而不是复制一个（事实上Mutex也不可复制）
	};


} // namespace lzweb


//后面可以测试下MutexLockGuard(x)产生的错误？？

// Prevent misuse like:
// MutexLockGuard(mutex_);
// A tempory object doesn't hold the lock for long!
#define MutexLockGuard(x) error "Missing guard object name"

#endif //MYWEBLIB_BASE_MUTEX_H_
